from tkinter import *
import serial
import os
import time
# 2021-06-16 16:48  by 炸天帮成员
# 综合修改自 _9_iciba_POST_0_with_TK.py 和 serialPort_demo_0.py
# 即serialPort_demo_0.py的带GUI版本
# 1.注意bind键盘时，需要另外写一个带有self参数的函数，该函数可以指向你想要的函数。
# 2.使用pack()或者place(x= ,y = ,width = ,height =)时只能选其中一个，要么全部使用pack()来生成组件，要么全部使用place()来生成组件。
# 关于place()的文档可以参考 http://www.weixueyuan.net/a/562.html

def SerialData_SendFromEntry():
    global user_input_Entry
    serial_ports = os.popen('python -m serial.tools.list_ports').read().strip() # 调用控制台并读取cmd命令行的结果
    #print('serial_ports = ',serial_ports)           # 显示当前有效的COM端
    serial_ports_var = StringVar()
    serial_ports_var.set(f'当前端口为：{serial_ports}')
    serial_ports_label = Label(frame,textvariable = serial_ports_var)
    serial_ports_label.pack()   #   虽然可以添加side="left"之类的，但需要修改一下全部组件pack()值。

    ser = serial.Serial()                                   # 实例化serial_com端口
    ser.port = serial_ports                             # 设置端口号
    ser.baudrate = 115200                           # 设置端口的波特率
    ser.bytesize = serial.EIGHTBITS
    ser.parity = serial.PARITY_NONE
    ser.stopbits = serial.STOPBITS_ONE
    ser.timeout = 1.0                                   # 设定读取超时时间 1s
    ser.xonxoff=False
    ser.rtscts=False
    ser.write_timeout=1.0                           # Set a write timeout value.
    ser.dsrdtr=False
    ser.inter_byte_timeout=None
    #print(ser)                                              # 输出当前端口的详细信息

    ser.open()                                            # 开启端口
    if ser.is_open :
        now_time = time.ctime(time.time())
        EntryValue = user_input_Entry.get()
        send_bytes = bytes(EntryValue+ f" {now_time}",encoding = 'UTF-8')            # 可以使用len(send_string)来查看发送了多少字节
        ser.write(send_bytes)                      # 发送数据至下位机
        data_return = ser.read(100)            # 按字节数读取来自下位机的串口内容，此处设定为100字节
        
        Entry_Scroll_2 = Scrollbar(frame,orient= HORIZONTAL)  # 带X轴方向滚动条的输入框
        return_data_Entry = Entry(frame,width = 400, xscrollcommand = Entry_Scroll_2.set)
        return_data_Entry.insert(0,data_return.decode('UTF-8')) # 如果不使用decode来解析bytes的话，将会返回\x型的16进制数据。
        return_data_Entry.pack()
        Entry_Scroll_2.pack(fill = X)
        Entry_Scroll_2.config(command = return_data_Entry.xview)
        
        #print('data_return = ',data_return)       # 显示从COM端读取到的内容
    ser.close()

def SerialData_SendFromEntry_for_bind(self):    #   用于指向和button功能相同的函数，tkinter的控件绑定按键就必须这样做。
    SerialData_SendFromEntry()
    
if __name__ == "__main__":
    root = Tk()
    root.geometry("400x400")
    root.title("serial_port串口通信")
    frame = Frame(root)
    frame.pack()
##    frame.place(x=0,y=0,width=400,height=400)

    label_var = StringVar()
    label_var.set('输入你想要发送的内容：')
    label = Label(frame,textvariable = label_var)
    label.pack()
##    label.place(x=0,y=0)

    user_input_Entry_Scroll = Scrollbar(frame,orient= HORIZONTAL)  # 带X轴方向滚动条的输入框
    user_input_Entry = Entry(frame,width = 400, xscrollcommand = user_input_Entry_Scroll.set)
    user_input_Entry.bind('<Return>',SerialData_SendFromEntry_for_bind)
    #【注意】：当绑定键盘后，触发的函数参数中必须带有self，既需要我们另外再起一个带self的函数，用于指向有相同功能的，不带self的函数。
    user_input_Entry.pack()
    user_input_Entry_Scroll.pack(fill = X)
##    user_input_Entry.place(x=0,y=20,height=20)
##    user_input_Entry_Scroll.place(x=0,y=40)
    user_input_Entry_Scroll.config(command = user_input_Entry.xview)

    button = Button(frame,text = "发送",command = SerialData_SendFromEntry) # 当按钮按下后，执行getFromEntry()函数中的iciba爬取内容
    button.pack()
##    button.place(x=150,y=200,width = 80,height = 40)

    root.mainloop()
